package com.yfp.device.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.gson.Gson;
import com.hy.corecode.idgen.WFGIdGenerator;
import com.yfp.common.core.constant.CacheConstants;
import com.yfp.common.core.enums.OrderTypeEnum;
import com.yfp.common.core.enums.PackageStatusEnums;
import com.yfp.common.core.enums.PayStatusEnum;
import com.yfp.common.core.enums.PayTypeEnum;
import com.yfp.common.core.utils.DateUtils;
import com.yfp.common.core.utils.StringUtils;
import com.yfp.common.redis.service.RedisService;
import com.yfp.common.redis.utils.RedisDelayQueueUtil;
import com.yfp.common.redis.utils.RedisLock;
import com.yfp.common.security.utils.SecurityUtils;
import com.yfp.device.config.PayProperties;
import com.yfp.device.controller.database.redis.DevicePreOrderRedis;
import com.yfp.device.domain.*;
import com.yfp.device.domain.dto.OrderCreateDTO;
import com.yfp.device.domain.dto.UploadWorkOrderRequest;
import com.yfp.device.domain.vo.DeviceActionStatusMakeVO;
import com.yfp.device.domain.vo.DeviceComboPreOrderStatusVO;
import com.yfp.device.domain.vo.MachineBaseInfoVo;
import com.yfp.device.domain.vo.OrderCreateVO;
import com.yfp.device.enums.GoodsTypeEnum;
import com.yfp.device.enums.OrderStatus;
import com.yfp.device.enums.PackageStatus;
import com.yfp.device.mapper.*;
import com.yfp.device.service.*;
import com.yfp.device.utils.AlipayUtils;
import com.yfp.device.utils.AppUserAgentUtils;
import com.yfp.minapp.auth.api.RemoteClientService;
import com.yfp.operation.api.RemoteOperationService;
import com.yfp.system.api.domain.SysUser;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.jetbrains.annotations.NotNull;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {

    @Resource
    private DevicePreOrderRedis devicePreOrderRedis;
    @Resource
    private OrderDetailMapper orderDetailMapper;
    @Resource
    private RemoteOperationService remoteOperationService;
    @Resource
    private OrderDetailService orderDetailService;
    @Resource
    private OrderListMapper orderListMapper;
    @Resource
    private OrderDetailWaitService orderDetailWaitService;

    @Resource
    private RedisLock redisLock;
    @Resource
    private RedisService redisService;
    @Resource
    private DeviceCurrentComboStockService deviceCurrentComboStockService;
    @Resource
    private MachineService machineService;
    @Resource
    private WFGIdGenerator wFGIdGenerator;
    @Resource
    private ComboService comboService;
    @Resource
    private ImgResourceService imgResourceService;
    @Resource
    private ClientService clientService;
    @Resource
    private AreaService areaService;
    @Resource
    private RouteService routeService;
    @Resource
    private PositionService positionService;
    @Resource
    private CompanyService companyService;
    @Resource
    private TagComboService tagComboService;
    @Resource
    private OrderComboService orderComboService;
    @Resource
    private OrderListService orderListService;
    @Resource
    private PayProperties payProperties;
    @Resource
    private HttpServletResponse httpResponse;
    @Resource
    private RedisDelayQueueUtil redisDelayQueueUtil;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private RedisTemplate<String, String> redisTemplate;
    @Resource
    private RemoteClientService remoteClientService;

    private final MachineMapper machineMapper;

    private final CompanyMapper companyMapper;

    private final AreaMapper areaMapper;

    private final RouteMapper routeMapper;

    private final PositionMapper positionMapper;

    private final ComboMapper comboMapper;

    private final SqlSessionFactory sqlSessionFactory;

    private final WorkOrderMapper workOrderMapper;

    private final DeviceCurrentComboPlanRoadMapper deviceCurrentComboPlanRoadMapper;

    private final DeviceCurrentComboPlanStockMapper deviceCurrentComboPlanStockMapper;


    public OrderServiceImpl(MachineMapper machineMapper, CompanyMapper companyMapper, AreaMapper areaMapper, RouteMapper routeMapper, PositionMapper positionMapper, ComboMapper comboMapper, SqlSessionFactory sqlSessionFactory, WorkOrderMapper workOrderMapper, DeviceCurrentComboPlanRoadMapper deviceCurrentComboPlanRoadMapper, DeviceCurrentComboPlanStockMapper deviceCurrentComboPlanStockMapper) {

        this.machineMapper = machineMapper;
        this.companyMapper = companyMapper;
        this.areaMapper = areaMapper;
        this.routeMapper = routeMapper;
        this.positionMapper = positionMapper;
        this.comboMapper = comboMapper;
        this.sqlSessionFactory = sqlSessionFactory;
        this.workOrderMapper = workOrderMapper;
        this.deviceCurrentComboPlanRoadMapper = deviceCurrentComboPlanRoadMapper;
        this.deviceCurrentComboPlanStockMapper = deviceCurrentComboPlanStockMapper;
    }

    /**
     * 生成订单数据
     *
     * @return 响应体
     */
    @Override
    public R<?> genOrderData(String dateString, Integer days) {
        try {
            // 准备数据
            // 获取机器列表
            List<MachineBaseInfoVo> machineBaseInfoVos = new ArrayList<MachineBaseInfoVo>();
            List<Machine> machines = machineMapper.selectAll();
            machines.forEach(m -> {
                try {
                    Company company = companyMapper.selectByPrimaryKey(m.getCompanyId());
                    Area area = areaMapper.selectByPrimaryKey(m.getAreaId());
                    Route route = routeMapper.selectByPrimaryKey(m.getRouteId());
                    Position position = positionMapper.selectByPrimaryKey(m.getPositionId());
                    MachineBaseInfoVo machineBaseInfoVo = new MachineBaseInfoVo();
                    machineBaseInfoVo.setMachineSn(m.getMachineId());
                    machineBaseInfoVo.setCompanyId(m.getCompanyId());
                    machineBaseInfoVo.setCompanyName(company.getName());
                    machineBaseInfoVo.setAreaId(m.getAreaId());
                    machineBaseInfoVo.setAreaName(area.getName());
                    machineBaseInfoVo.setRouteId(m.getRouteId());
                    machineBaseInfoVo.setRouteName(route.getName());
                    machineBaseInfoVo.setPositionId(m.getPositionId());
                    machineBaseInfoVo.setPositionName(position.getPositonName());
                    machineBaseInfoVo.setPositionAddr(m.getPositionAddr());

                    machineBaseInfoVos.add(machineBaseInfoVo);
                } catch (Exception e) {
                    log.error("获取机器列表异常继续");
                }
            });
            int machineBaseInfoSize = machineBaseInfoVos.size();
            // 获取套餐数据
            List<Combo> combos = comboMapper.selectAll();
            int comboSize = combos.size();

            ArrayList<OrderList> orderLists = new ArrayList<>();

            SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false);

            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
            Date initDate = formatter.parse(dateString);
            for (int i = 0; i < days; i++) {
                Date localDate = DateUtils.addDays(initDate, i);
                String localDateStr = DateUtils.parseDateToStr("yyyy-MM-dd", localDate);
                log.info("\"{} 08:30:00\", \"{} 11:30:00\"", localDateStr, localDateStr);
                extracted(sqlSession, localDateStr + " 08:30:00", localDateStr + " 11:30:00", 70, machineBaseInfoVos, machineBaseInfoSize, combos, comboSize, orderLists);

                log.info("\"{} 11:30:00\", \"{} 12:30:00\"", localDateStr, localDateStr);
                extracted(sqlSession, localDateStr + " 11:30:00", localDateStr + " 12:30:00", 800, machineBaseInfoVos, machineBaseInfoSize, combos, comboSize, orderLists);

                log.info("\"{} 12:30:00\", \"{} 17:30:00\"", localDateStr, localDateStr);
                extracted(sqlSession, localDateStr + " 12:30:00", localDateStr + " 17:30:00", 90, machineBaseInfoVos, machineBaseInfoSize, combos, comboSize, orderLists);

                log.info("\"{} 17:30:00\", \"{} 19:30:00\"", localDateStr, localDateStr);
                extracted(sqlSession, localDateStr + " 17:30:00", localDateStr + " 19:30:00", 200, machineBaseInfoVos, machineBaseInfoSize, combos, comboSize, orderLists);

                log.info("\"{} 19:30:00\", \"{} 20:30:00\"", localDateStr, localDateStr);
                extracted(sqlSession, localDateStr + " 19:30:00", localDateStr + " 20:30:00", 55, machineBaseInfoVos, machineBaseInfoSize, combos, comboSize, orderLists);
            }

            return R.ok("生成订单数据成功");
        } catch (Exception e) {
            log.error("生成订单数据失败", e);
            return R.fail("生成订单数据失败");
        }
    }


    private void extracted(SqlSession sqlSession, String beginTime, String endTime, int size, List<MachineBaseInfoVo> machineBaseInfoVos, int machineBaseInfoSize, List<Combo> combos, int comboSize, ArrayList<OrderList> orderLists) throws ParseException {
        size = RandomUtils.nextInt(size - 5, size + 20);

        for (int i = 0; i < size; i++) {
            // 1、生成订单编号
            Date orderTime = randomDate(beginTime, endTime);
            Date payTime = DateUtils.addSeconds(orderTime, RandomUtils.nextInt(3, 20));

            // 2、生成用户名
            String userName = UUID.randomUUID().toString();

            // 3、取机器数据
            MachineBaseInfoVo machineBaseInfoVo = machineBaseInfoVos.get(RandomUtils.nextInt(0, machineBaseInfoSize));

            // 4、取套餐数据
            Combo combo = combos.get(RandomUtils.nextInt(0, comboSize));

            OrderList orderList = new OrderList();
            orderList.setOrderSn(orderTime.getTime() + "");
            orderList.setOrderTime(orderTime);
            orderList.setUserName(userName);
            orderList.setAmt(combo.getSalePrice());
            orderList.setPayType(RandomUtils.nextInt(1, 3) + "");
            orderList.setPayStatus(RandomUtils.nextInt(1, 7));
            orderList.setPayTime(payTime);
            orderList.setComboId(combo.getComboId());
            orderList.setComboName(combo.getName());
            orderList.setMachineId(machineBaseInfoVo.getMachineSn());
            orderList.setCompanyId(machineBaseInfoVo.getCompanyId());
            orderList.setCompanyName(machineBaseInfoVo.getCompanyName());
            orderList.setAreaId(machineBaseInfoVo.getAreaId());
            orderList.setAreaName(machineBaseInfoVo.getAreaName());
            orderList.setRouteId(machineBaseInfoVo.getRouteId());
            orderList.setRouteName(machineBaseInfoVo.getRouteName());
            orderList.setPositionId(machineBaseInfoVo.getPositionId());
            orderList.setPositionName(machineBaseInfoVo.getPositionName());
            orderList.setPositionAddr(machineBaseInfoVo.getPositionAddr());
            orderList.setIsException("1");
            orderList.setOrderType("1");
            orderList.setRemark("1001");

            orderLists.add(orderList);
            if (orderLists.size() > 500) {
                log.info("开始批量插入");
                OrderListMapper orderMapper = sqlSession.getMapper(OrderListMapper.class);
                orderLists.forEach(orderMapper::insertSelective);
                sqlSession.commit();
                sqlSession.clearCache();
                orderLists.clear();

                log.info("结束批量插入");
            }
            log.info(i + "");
        }

        log.info("开始批量插入.");
        OrderListMapper orderMapper = sqlSession.getMapper(OrderListMapper.class);
        orderLists.forEach(orderMapper::insertSelective);
        sqlSession.commit();
        sqlSession.clearCache();
        orderLists.clear();
        log.info("结束批量插入.");
    }

    private Date randomDate(String beginDate, String endDate) throws ParseException {

        // 时间格式化
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // 定义开始时间
        Date start = format.parse(beginDate);
        // 定义结束时间
        Date end = format.parse(endDate);
        if (start.getTime() >= end.getTime()) {
            return null;
        }
        long date = random(start.getTime(), end.getTime());
        return new Date(date);
    }

    private static long random(long begin, long end) {

        long rtn = begin + (long) (Math.random() * (end - begin));
        // 如果返回的是开始时间和结束时间，通过递归调用本函数查找随机值
        if (rtn == begin || rtn == end) {
            return random(begin, end);
        }
        return rtn;
    }

    /**
     * 上传工单
     *
     * @param request 请求体
     * @return 响应体
     */
    @Transactional
    public R<?> uploadWorkOrder(UploadWorkOrderRequest request) {
        log.info("上传工单：{}", request);
        WorkOrder workOrder = getWorkOrder(request);
        RLock lock = redissonClient.getLock("uploadWorkOrder" + workOrder.getOrderDetailId());
        try {
            while (true) {
                if (lock.tryLock() == false) {
                    Thread.sleep(300);
                    continue;
                }
                if (StringUtils.isEmpty(workOrder.getOrderDetailId())) {
                    return R.fail("orderDetailId为空！");
                }
                if (workOrderMapper.selectByOrderDetailId(request.getOrderDetailId()) == null) {
                    log.info("插入工单：订单号{},货道号:{}", request.getOrderSn(), request.getRoadNo());
                    workOrderMapper.insertSelective(workOrder);
                } else {
                    log.info("更新工单：订单号{}，状态{},货道号:{}", request.getOrderSn(), request.getWorkerOrderStatus(), request.getRoadNo());
                    workOrderMapper.updateByOrderDetailId(workOrder);
                    // workOrderMapper.updateWorkOrderStatus(request.getOrderDetailId(),  request.getWorkerOrderStatus(), request.getExitCloseTime());
                }
                // 3：已完成
                if ("3".equals(request.getWorkerOrderStatus())) {
                    orderListService.updateFinishTimeByOrderDetailId(request.getOrderDetailId(), request.getExitCloseTime());
                }
                orderListMapper.updateMachineRoadNo(request.getOrderDetailId(), request.getRoadNo());
                if ("3".equals(request.getWorkerOrderStatus()) || "4".equals(request.getWorkerOrderStatus())) {
                    log.info("更新货道库存：订单号{}", request.getOrderSn());
                    deviceCurrentComboPlanRoadMapper.updateInventoryByComboIdAndRoadNo(request.getMachineSn(), request.getComboId(), request.getRoadNo());
                    // if (StringUtils.isNotEmpty(request.getOrderDetailId())){
                    //     log.info("完成工单，订单详情ID：{}", request.getOrderDetailId());
                    //     orderDetailWaitService.updateStatusByOrderDetailId(request.getOrderDetailId(), 1);
                    // }
                }
                log.info("上传工单成功：订单号{}", request.getOrderSn());
                lock.unlock();
                return R.ok("上传工单成功");
            }
        } catch (Exception e) {
            log.error("上传工单失败", e);
            lock.unlock();
            return R.fail("上传工单失败");
        }
    }

    @NotNull
    private static WorkOrder getWorkOrder(UploadWorkOrderRequest request) {
        WorkOrder workOrder = new WorkOrder();
        workOrder.setOrderSn(request.getOrderSn());
        workOrder.setMachineId(request.getMachineSn());
        workOrder.setWorkerOrderStatus(request.getWorkerOrderStatus());
        workOrder.setExitCloseTime(request.getExitCloseTime());
        workOrder.setHeatBeginTime(request.getHeatBeginTime());
        workOrder.setHeatEndTime(request.getHeatEndTime());
        workOrder.setInLockerTime(request.getInLockerTime());
        workOrder.setOutLockerTime(request.getOutLockerTime());
        workOrder.setProcessTime(request.getProcessTime());
        workOrder.setTemperature(request.getTemperature());
        workOrder.setCreateTime(new Date());
        workOrder.setIsDelete(false);
        workOrder.setWorkOrderSn(request.getOrderDetailId());
        workOrder.setComboId(request.getComboId());
        workOrder.setComboName(request.getComboName());
        workOrder.setWorkOrderNo(request.getWorkOrderNo());
        workOrder.setOutMeal(request.getOutMeal());
        workOrder.setOrderDetailId(request.getOrderDetailId());
        workOrder.setRoadNo(request.getRoadNo());
        return workOrder;
    }


    /**
     * 设备下单发起制作
     *
     * @param orderCombo
     * @return
     */
    @Override
    @Transactional
    public R<DeviceActionStatusMakeVO> deviceActionStatusMake(OrderCombo orderCombo) {
        String orderId = orderCombo.getOrderId();
        if (orderId == null) {
            log.info("参数不完整,orderId:{}", orderId);
            return R.fail("参数不完整");
        }
        List<OrderList> orderList = orderListMapper.getByPayOrderId(orderId);
        if (orderList.isEmpty()) {
            log.info("设备发起套餐制作失败,原因:未支付,订单id:{}", orderId);
            return R.fail("设备发起套餐制作失败");
        }

        LambdaQueryWrapper<OrderDetail> wrapper = new LambdaQueryWrapper<OrderDetail>().eq(OrderDetail::getOrderId, orderId);
        List<OrderDetail> orderDetails = orderDetailMapper.selectList(wrapper);
        if (orderDetails.isEmpty()) {
            return R.fail();
        }
        if (StringUtils.isNotEmpty(orderList.get(0).getUserMobile())) {
            String pickupNum = "";
            Integer num = 1;
            for (OrderDetail orderDetail : orderDetails) {
                // 组装取餐码
                if (num < 10) {
                    pickupNum = pickupNum + "-0" + num;
                } else {
                    pickupNum = pickupNum + "-" + num;
                }
                num++;
                orderDetail.setPickupNum(orderList.get(0).getUserMobile().substring(7, 11) + pickupNum);
            }
        }
//        Timestamp queueTime = new Timestamp(System.currentTimeMillis());
//
//        List<RedisOrderDetail> redisOrderDetails = new ArrayList<>();
//        RedisOrderDetail addRedisOrderDetail = null;
//        for (OrderDetail detail : orderDetails) {
//            detail.setUpdateTime(new Timestamp(System.currentTimeMillis()));
//            detail.setStatus(PackageStatus.WaitingToBeMade.getStatus());
//            detail.setQueueTime(queueTime);
//            addRedisOrderDetail = new RedisOrderDetail();
//            addRedisOrderDetail.setDetailId(detail.getOrderDetailId());
//            addRedisOrderDetail.setQueueTime(queueTime);
//            redisOrderDetails.add(addRedisOrderDetail);
//        }
//
//        remoteOperationService.checkMachineMealMinAnomaly(redisOrderDetails);
//
//        orderDetailService.batchUpdate(orderDetails);

        SysUser sysUser = SecurityUtils.getLoginUser().getSysUser();
        DeviceActionStatusMakeVO deviceActionStatusMakeVO = new DeviceActionStatusMakeVO();
        if (sysUser != null) {
            // 头像
            deviceActionStatusMakeVO.setUserHeadUrl(sysUser.getAvatar());
            // 电话
            deviceActionStatusMakeVO.setPickupNum(sysUser.getPhonenumber());
        }

        String redisMake = redisTemplate.opsForValue().get("makePackage" + orderId);
        deviceActionStatusMakeVO.setPackageList(orderDetails);
        deviceActionStatusMakeVO.setPickupGoodsType(StringUtils.isEmpty(redisMake) ? "2FO" : "2TS");
        deviceActionStatusMakeVO.setOrderId(orderId);
        return R.ok(deviceActionStatusMakeVO);
    }


    /**
     * 查询订单支付状态
     *
     * @param preOrderId
     * @return
     */
    @Override
    public R<DeviceComboPreOrderStatusVO> getDeviceComboPreOrderStatus(String preOrderId) {
        Optional<DevicePreOrder> devPreOr = devicePreOrderRedis.getDevicePreOrder(preOrderId);
        if (devPreOr.isEmpty()) {
            log.info("设备获取设备预支付订单状失败,原因:该预支付订单已经失效了,预支付订单id:{}", preOrderId);
            return R.fail("设备获取设备预支付订单状失败");
        }
        DevicePreOrder devicePreOrder = devPreOr.get();
        String deviceId = devicePreOrder.getDeviceId();
        String itemOrderNum = devicePreOrder.getItemOrderNum();
        // 获取状态为支付的订单
        List<OrderList> orderList = orderListMapper.getByPayOrderId(itemOrderNum);


        // 返回数据
        DeviceComboPreOrderStatusVO statusVO = new DeviceComboPreOrderStatusVO();
        statusVO.setOrderId(itemOrderNum);
        statusVO.setPreOrderId(preOrderId);
        statusVO.setPayStatus(true);
        if (orderList.isEmpty()) {
            statusVO.setPayStatus(false);
        }
        log.info("设备获取设备预支付订单状态成功，设备id信息:{},返回信息:{}", deviceId, statusVO);
        return R.ok(statusVO);
    }

    /**
     * 获取预支付订单（设备拉起支付操作）
     *
     * @param orderCreateDTO
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderCreateVO deviceComboPreOrderCreate(OrderCreateDTO orderCreateDTO) {
        log.info("设备发起套餐下单,参数:{}", orderCreateDTO);
        String machineId = SecurityUtils.getUsername();
        // String machineId = "2401250100004";

        Assert.isTrue(CollUtil.isNotEmpty(orderCreateDTO.getComboList()), "参数不完整");

        // 下单锁
        String lockKey = CacheConstants.MINAPP_ORDER_CREATE_LOCK_KEY + machineId;
        RLock lock = redissonClient.getLock(lockKey);
        Assert.isTrue(lock.tryLock(), "稍后重试");

        try {
            // 校验库存
            Boolean isStockAvailable = deviceCurrentComboStockService.checkStockAvailability(orderCreateDTO.getComboList(), machineId);
            Assert.isTrue(isStockAvailable, "套餐库存不足");

            // 封装订单主表数据
            Machine machine = machineService.findByMachineId(machineId);
            Timestamp timestamp = new Timestamp(System.currentTimeMillis());
            OrderCombo orderCombo = new OrderCombo();
            orderCombo.setOrderId(String.valueOf(wFGIdGenerator.next()));
            orderCombo.setMachineId(machine.getMachineId());
            orderCombo.setMachineName(machine.getMachineName());
            orderCombo.setUserId(machine.getMachineId());
            orderCombo.setStatus(OrderStatus.ToBePaid.getStatus());
            orderCombo.setReplacementState(0);
            orderCombo.setCupboardState(0);
            orderCombo.setCreateTime(timestamp);
            orderCombo.setUpdateTime(timestamp);
            orderCombo.setGoodsType(GoodsTypeEnum.ENTITY.getCode());
            orderCombo.setCityName(machine.getCityName());

            List<String> packageIds = orderCreateDTO.getComboList().stream().map(OrderCreateDTO.ShopCart::getComboId).collect(Collectors.toList());
            Map<String, Combo> ComboMapById = comboService.listByPackageIds(packageIds).stream().collect(Collectors.toMap(Combo::getComboId, payload -> payload));
            Map<String, ImgResource> imgResourceMapById = imgResourceService.listByThumbIds(ComboMapById.values().stream().map(Combo::getThumb).collect(Collectors.toList())).stream().collect(Collectors.toMap(ImgResource::getImgId, payload -> payload));

            // 封装订单子表数据
            List<OrderDetail> orderDetails = orderCreateDTO.getComboList().stream().map(item -> {
                Combo combo = ComboMapById.getOrDefault(item.getComboId(), new Combo());
                ImgResource imgResource = imgResourceMapById.getOrDefault(combo.getThumb(), new ImgResource());
                List<OrderDetail> orderDetailsTemp = CollUtil.newArrayList();
                for (int i = 0; i < item.getCount(); i++) {
                    OrderDetail orderDetail = new OrderDetail();
                    orderDetail.setOrderDetailId(String.valueOf(wFGIdGenerator.next()));
                    orderDetail.setOrderId(orderCombo.getOrderId());
                    orderDetail.setPackageId(item.getComboId());
                    orderDetail.setPackageName(combo.getName());
                    orderDetail.setIsHeatAdditive(true);
                    orderDetail.setHeatTime(combo.getHeatTime().longValue());
                    orderDetail.setStatus(PackageStatusEnums.PendingPayment.getStatus());
                    orderDetail.setApplietAmount(combo.getSalePrice());
                    orderDetail.setDeviceAmount(combo.getSalePrice());
                    orderDetail.setThumbUrl(imgResource.getUrl());
                    orderDetail.setCompletedCount(0L);
                    orderDetail.setPickedUpCount(0L);
                    orderDetail.setCount(1L);
                    orderDetail.setCreateTime(timestamp);
                    orderDetail.setUpdateTime(timestamp);
                    orderDetail.setQueueTime(timestamp);
                    orderDetail.setCityName(machine.getCityName());
                    orderDetailsTemp.add(orderDetail);
                }
                return orderDetailsTemp;
            }).flatMap(Collection::stream).toList();
            // 统计设备价格
            BigDecimal totalPrice = orderDetails.stream().map(item -> new BigDecimal(item.getDeviceAmount())).reduce(BigDecimal.ZERO, BigDecimal::add);
            orderCombo.setPrice(totalPrice.toString());

            // 封装orderList数据
            // Client client = clientService.getById(userId);
            Area area = areaService.getById(machine.getAreaId());
            Route route = routeService.getById(machine.getRouteId());
            Position position = positionService.getById(machine.getPositionId());
            Company company = companyService.getById(machine.getCompanyId());
            List<OrderList> orderLists = orderDetails.stream().map(item -> {
                Combo combo = ComboMapById.getOrDefault(item.getPackageId(), new Combo());
                OrderList orderList = new OrderList();
                orderList.setId(item.getOrderDetailId());
                orderList.setOrderSn(orderCombo.getOrderId());
                orderList.setOrderTime(timestamp);
                orderList.setUserName(machine.getMachineName());
                // orderList.setUserMobile(client.getMobile());
                orderList.setAmt(item.getDeviceAmount());
                orderList.setPayType(PayTypeEnum.WeChatPay.getCode().toString());
                orderList.setPayStatus(PayStatusEnum.UNPAID.getCode());
                orderList.setComboId(combo.getComboId());
                orderList.setComboName(combo.getName());
                String tagIds = combo.getTagId();
                List<String> tagIdList = StrUtil.split(tagIds, ",");
                if (CollUtil.isNotEmpty(tagIdList)) {
                    String tagNames = tagComboService.listByIds(tagIdList).stream().map(TagCombo::getTagName).collect(Collectors.joining(","));
                    orderList.setComboTag(tagNames);
                }
                orderList.setMachineId(orderCombo.getMachineId());
                orderList.setCompanyId(machine.getCompanyId());
                orderList.setCompanyName(company.getName());
                orderList.setAreaId(machine.getAreaId());
                orderList.setAreaName(area.getName());
                orderList.setRouteId(machine.getRouteId());
                orderList.setRouteName(route.getName());
                orderList.setPositionId(machine.getPositionId());
                orderList.setPositionName(position.getPositonName());
                orderList.setPositionAddr(machine.getPositionAddr());
                orderList.setIsException("1");
                orderList.setOrderType(OrderTypeEnum.Device.getCode().toString());
                orderList.setUpdateTime(timestamp);
                orderList.setUpdateName(machine.getMachineName());
                orderList.setCount(1L);
                orderList.setGoodsType(GoodsTypeEnum.ENTITY.getCode());
                orderList.setCityName(machine.getCityName());
                return orderList;
            }).collect(Collectors.toList());

            // 更新库存
            deviceCurrentComboStockService.decreaseStockQuantity(orderCreateDTO.getComboList(), machineId);
            // 更新订单数据
            orderComboService.save(orderCombo);
            orderDetailService.saveBatch(orderDetails);
            orderListService.saveBatch(orderLists);

            // 将订单信息加入到延迟队列。如果超时没有支付，取消订单，恢复库存
            Gson gson = new Gson();
            gson.toJson(orderCombo);
            String json = gson.toJson(orderCombo);
            redisDelayQueueUtil.addDelayQueue(json, 3, TimeUnit.MINUTES, CacheConstants.MINAPP_ORDER_CREATE_DELAY_QUEUE_KEY);

            String application = payProperties.getQrCodeRoute().concat(orderCombo.getOrderId());
            OrderCreateVO orderCreateVO = new OrderCreateVO();
            orderCreateVO.setPreOrderId(orderCombo.getOrderId());
            orderCreateVO.setQrCodeUrl(application);
            return orderCreateVO;
        } finally {
            lock.unlock();
        }
    }

    /**
     * 获取预支付订单（设备拉起支付操作）
     *
     * @param userAgent
     * @param sessionId
     * @return
     */
    @Override
    public String payChanelApply(String userAgent, String sessionId) {
        log.info("用户使用支付App扫描,Session Id:{},User-Agent的值:{}", sessionId, userAgent);
        var payAppType = AppUserAgentUtils.getPayAppType(userAgent);
        if (payAppType.isEmpty()) {
            log.warn("用户使用支付宝微信等之外的非支付App扫描,Session Id:{},User-Agent的值:{}", sessionId, userAgent);
            httpResponse.setStatus(405);
            return "Please use WeChat or Alipay payment app to scan.";
        }
        if (sessionId == null) {
            log.warn("用户访问聚合支付接口,但是session id为空");
            httpResponse.setStatus(404);
            return "Illegal Requests";
        }

        // 返回对应的支付二维码
        switch (payAppType.get()) {
            case Alipay -> {
                String url = payProperties.getQrCodeFrontendService() + "alipay_qrcode/?session_id=" + sessionId;
                log.info("用户使用支付宝扫描了二维码,返回去访问地址为:{}", url);
                return AlipayUtils.intAlipayScanTheQRCodeRespContent(url);
            }
            case WeChatPay -> {
                String url = payProperties.getQrCodeFrontendService() + "wxpay_qrcode/?session_id=" + sessionId;
                log.info("用户使用微信扫描了二维码,返回去访问地址为:{}", url);
                return AlipayUtils.intAlipayScanTheQRCodeRespContent(url);
            }
        }
        log.warn("用户使用支付宝微信等之外的非支付App扫描,User-Agent的值:{}", userAgent);
        return "Please use WeChat or Alipay payment app to scan.";
    }

    /**
     * 修改订单状态
     *
     * @param orderDetailIds
     */
    @Override
    public void updateOrderStatus(List<String> orderDetailIds) {

        log.info("修改订单状态参数，订单详情id列表:{}", orderDetailIds);

        for (String orderDetailId : orderDetailIds) {

            // 根据详情id获取订单信息，查看状态是否为已支付状态
            OrderList orderList = orderListMapper.getById(orderDetailId);
            if (!BeanUtil.isEmpty(orderList) && orderList.getPayStatus() == 8) {
                orderListMapper.updateOrderStatus(orderDetailId);
                orderDetailMapper.updateOrderStatus(orderDetailId);

                // 判断该订单的所有
                Boolean b = orderDetailMapper.isAccomplish(orderDetailId);
                if (b) {
                    OrderDetail orderDetail = orderDetailMapper.selectById(orderDetailId);
                    OrderCombo orderCombo = new OrderCombo();
                    orderCombo.setOrderId(orderDetail.getOrderId());
                    orderCombo.setStatus("Finish");
                    orderComboService.updateOrderStatus(orderCombo);
                }
            }
        }
    }

    @Override
    public void wxNotify(UploadWorkOrderRequest request) {
        log.info("wxNotify：订单request:{}", request);
        if ("2".equals(request.getWorkerOrderStatus())) {
            // 状态2发送，避免重复发送判断是否已经发送过通知，如果发送过则不再发送
            boolean noHasSent = !redisService.hasKey(CacheConstants.MINAPP_ORDER_STATUS_NOTIFYCOOKINGSTATUS_KEY + request.getOrderSn());
            log.info("wxNotify：是否发送通知:{}，订单编号:{},订单详情编号:{}", noHasSent, request.getOrderSn(), request.getOrderDetailId());
            if (noHasSent) {
                remoteClientService.notifyCookingStatus(request.getOrderSn(), request.getOrderDetailId());
                redisService.setCacheObject(CacheConstants.MINAPP_ORDER_STATUS_NOTIFYCOOKINGSTATUS_KEY + request.getOrderSn(), PackageStatus.InTheMaking.getStatus(), 12L, TimeUnit.HOURS);
            }
        }
    }
}

